package com.ykh.service.impl;

import com.alibaba.fastjson.JSON;
import com.auth0.jwt.interfaces.Claim;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ykh.mapper.VideoMapper;
import com.ykh.pojo.dto.PageParams;
import com.ykh.pojo.dto.RegisterParam;
import com.ykh.pojo.po.User;
import com.ykh.mapper.UserMapper;
import com.ykh.pojo.po.Video;
import com.ykh.pojo.vo.*;
import com.ykh.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ykh.service.VideoService;
import com.ykh.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author ykh
 * @since 2023年10月26日
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private VideoMapper videoMapper;

    @Autowired
    private QiniuUtils qiniuUtils;

    //redis的对象
    @Autowired
    private RedisTemplate<String,String> redisTemplate;


    @Override
    public User getUserByAccount(String account) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getAccount, account);
        User user = userMapper.selectOne(queryWrapper);
        return user;
    }

    @Override
    public Result login(String account, String password) {
        //判断用户名密码是是否为空
        if (account == null || password == null || account.equals("") || password.equals("")) {
            return Result.fail(403, "账号或密码为空");
        }
        //判断用户名的正确性
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getAccount, account);
        //先根据账号判断用户名是否存在
        User user = userMapper.selectOne(queryWrapper);
        if (user == null) {
            return Result.fail(403, "用户名不存在");
        }

        //对传输过来的RSA密码用私钥进行解密
        String rawPassword = RSAUtil.decode(password, Constant.PRIVATE_KEY);

        //对数据库中的取到密钥进行解密
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();

        //判断密码的正确性(开启RSA使用上一个判断)
        if(bCryptPasswordEncoder.matches(rawPassword, user.getPassword())){
//        if (bCryptPasswordEncoder.matches(password, admin.getAdminPassword())) {
            //生成jwt
            Map<String, Object> map = new HashMap<>();
            map.put("user_account", user.getAccount());
            map.put("nick_name", user.getNickName());
            String token = Auth0JwtUtils.sign(map);
            redisTemplate.opsForValue().set("Token_"+token, JSON.toJSONString(user),1, TimeUnit.DAYS);
            //登录成功
            return Result.success(token);
        } else {
            return Result.fail(ErrorCode.PARAMS_ERROR.getCode(), ErrorCode.PARAMS_ERROR.getMsg());
        }
    }

    @Override
    @Transactional
    public Result register(RegisterParam registerParam) {
        /**
         * 1.判断是否合法
         * 2.判断账户是否存在,存在返回账户已经被注册
         * 3.不存在, 注册用户
         * 4.生成token
         * 5. 存入redis,并返回
         * 6. 注意加上事务, 一旦中间任何过程出现问题,需要回滚
         */
        //1.判断是否合法
        String account = registerParam.getAccount();
        String password = registerParam.getPassword();
        String nickName = registerParam.getNickName();
        String mobilePhoneNumber = registerParam.getMobilePhoneNumber();
        String email = registerParam.getEmail();

        if (StringUtils.isBlank(account)
                || StringUtils.isBlank(password)
                || StringUtils.isBlank(nickName)
                || StringUtils.isBlank(mobilePhoneNumber)
                || StringUtils.isBlank(email)
        ){
            return Result.fail(ErrorCode.PARAMS_ERROR.getCode(), ErrorCode.PARAMS_ERROR.getMsg());
        }
        //2.判断账户是否存在
        User user = getUserByAccount(account);
        if (user != null){
            return Result.fail(ErrorCode.ACCOUNT_EXIST.getCode(), ErrorCode.ACCOUNT_EXIST.getMsg());
        }
        //3.进行注册用户
        user = new User();
        user.setNickName(nickName);
        user.setAccount(account);
        user.setPassword(new BCryptPasswordEncoder().encode(password));
        user.setCreateDate(LocalDateTime.now());
        user.setAvatar(Constant.DEFAULT_AVATAR_ADDRESS);
        user.setMobilePhoneNumber(mobilePhoneNumber);
        user.setEmail(email);
        //保存新注册的账户到数据库
        userMapper.insert(user);
        //token
        Map<String, Object> map = new HashMap<>();
        map.put("user_account", user.getAccount());
        map.put("nick_name", user.getNickName());
        String token = Auth0JwtUtils.sign(map);
        redisTemplate.opsForValue().set("Token_"+token, JSON.toJSONString(user),1, TimeUnit.DAYS);
        return Result.success(token);
    }

    @Override
    public User checkToken(String token) {
        //1. 判断token是否合法
        if (StringUtils.isBlank(token)) {
            //不合法返回空
            return null;
        }
        //解析token
        if(!Auth0JwtUtils.verify(token)){
            return null;
        }
        Map<String, Claim> claims = Auth0JwtUtils.getClaims(token);
        if( claims == null) {
            return null;
        }
        String userAccount = String.valueOf(claims.get("user_account"));
        String nickName = String.valueOf(claims.get("nick_name"));
        log.info( "-------------jwt验证成功----------------");
        log.info("用户账号: "+ userAccount);
        log.info("用户昵称: "+ nickName);
        log.info("----------------------------------------");
        //将 登录的学生信息存入 本地线程中, 方便获取
        User user = new User(userAccount, nickName);
        UserThreadLocal.put(user);
        //解析成功,在redis中再查询验证
        String userJson = redisTemplate.opsForValue().get("Token_" + token);

        //判断 userJosn 是否为空,为空就是token过期了
        if( StringUtils.isBlank(userJson)) {
            return null;
        }

        //到这里, 说明校验通过
        user = JSON.parseObject(userJson,User.class);
        return user;
    }


    //根据评论人员的ID查询 作者的信息,并返回
    @Override
    public CommentUserVo findUserVoById(String userAccount) {
        User sysUser = userMapper.selectById(userAccount);
        //防止出现空指针
        if( sysUser ==null) {
            sysUser = new User();
            sysUser.setNickName("");
        }
        CommentUserVo commentUserVo = new CommentUserVo();
        BeanUtils.copyProperties(sysUser,commentUserVo);
        return commentUserVo;
    }

    /**
     * 根据用户ID获取用户完整功能信息
     * @param account
     * @return
     */
    @Override
    public UserVo getInfo(String account) {
        UserVo userVo = new UserVo();
        User user = userMapper.selectById(account);
        BeanUtils.copyProperties(user,userVo);
        userVo.setCreateDate(TimeUtil.getDateTimeAsString(user.getCreateDate()));
        userVo.setFansNum(user.getFansNum());
        return userVo;
    }

    /**
     * 退出登录
     * @param token
     * @return
     */
    @Override
    public boolean logout(String token) {
        redisTemplate.delete("Token_" + token);
        return true;
    }

    /**
     * 头像上传
     * @param avatarImage
     * @return
     */
    @Override
    public Result uploadAvatar(MultipartFile avatarImage, User user) {
        String fileName = UUID.randomUUID().toString() + "." +
                StringUtils.substringAfterLast(avatarImage.getOriginalFilename(), ".");
        String key = qiniuUtils.imageUpload(avatarImage, fileName);
        if (key != null){
            String imageUrl = Constant.IMAGE_URL + fileName;
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getAccount, user.getAccount());
            //更新数据库中视频的封面地址
            User user2 = userMapper.selectOne(queryWrapper);
            if(user2 == null){
                return Result.fail(ErrorCode.NO_EXIXT_USER.getCode(),ErrorCode.NO_EXIXT_USER.getMsg());
            }
            user2.setAvatar(imageUrl);
            userMapper.update(user2, queryWrapper);
            return Result.success(imageUrl);
        }
        return Result.fail(ErrorCode.IMAGE_UPLOAD_FAIL.getCode(), ErrorCode.IMAGE_UPLOAD_FAIL.getMsg());
    }
}
